<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>使用requestAnimationFrame所遇到的问题</title>
  <link rel="icon" type="image/png" href="../think/assets/ant.png">
  <link href="../styles.css" rel="stylesheet">
  <link href="../vs.css" rel="stylesheet">
  <!-- Global site tag (gtag.js) - Google Analytics -->
  <script async src="https://www.googletagmanager.com/gtag/js?id=UA-131906119-1"></script>
  <script>
    window.dataLayer = window.dataLayer || [];
    function gtag(){dataLayer.push(arguments);}
    gtag('js', new Date());

    gtag('config', 'UA-131906119-1');
  </script>
  <script async src="../index.js"></script>
</head>
<body>
<h1>使用requestAnimationFrame所遇到的问题</h1>
<p>今天在测试新版验证码时，发现了很多问题。大部分问题都是由于没有仔细排查，理清其中的逻辑。比如忘记了修改状态，导致forbidden和abuse后无法刷新。再比如由于在移动端点击一下可能触发两次刷新按钮，由于在刷新过程中没有修改状态做限制，导致一下子刷新了两次，造成slice和bg的缺口不对应。</p>
<p>其中，有一个有意思的问题。就是requestAnimationFrame函数，它的作用是：在运行到requestAnimationFrame(callback)时，callback会在浏览器下次页面刷新时被调用。那么所谓的下次刷新是什么时候呢？1/60秒后？</p>
<p>经过测试发现，如果在下次刷新之前离开了当前页面，那么离开期间不会调用callback（因为页面不会被刷新）。当再次回到这个页面时，callback会在刷新页面时调用。也就是说callback确实会在下一次的刷新中调用，但是下一次的刷新时间却不是固定的。</p>
<p>而我所写的canvas版验证码的绘画逻辑是：首先将callback设为加载过程，等所有图片都加载好了就将callback设为图片显示过程。在加载时，会首先把bar和footer区域内容绘画到画布上，然后在window区域中一直播放加载过程动画。</p>
<p>现在问题来了。如果在还没有开始调用加载过程就离开了这个页面。此时加载过程的callback将不会运行，但是这些图片可能在这个离开过程中被加载好，一旦加载好就会把图片显示过程设为callback，并把加载过程移除。</p>
<p>因此，如果在这之后再回来，那么加载过程实际上是不会执行。这样就导致了bar和footer区域都是空白的，因为图片显示过程中没有画bar和footer区域内容的子过程。</p>
<p>另外，在调用callback时，会给callback传递一个timestamp参数，表示从1970-1-1 00:00:00到当前时间所经历的毫秒数。制作动画帧时，以时间间隔为单位，比如1/24秒。这样就将1秒分成了24段，然后定义在第一段时间内画哪一帧，在第二段时间内画哪一帧。</p>
<p>这样的好处是，即使由于设备性能问题，不能将每一帧都绘画出来，也能保证整个动画的运动速度是一致的。如果用一次次往下画的方式，就会导致动画的运动速度不一致。而且由于每个设备刷新时间不同，很难选择两次之间刷新的时间间隔。</p>


</body>
</html>
